package com.abcdefg.webpagechatprojectbymyself.api;

import com.abcdefg.webpagechatprojectbymyself.component.OnlineUserMessage;
import com.abcdefg.webpagechatprojectbymyself.mapper.MessageMapper;
import com.abcdefg.webpagechatprojectbymyself.mapper.MessageSessionMapper;
import com.abcdefg.webpagechatprojectbymyself.model.Friend;
import com.abcdefg.webpagechatprojectbymyself.model.Message;
import com.abcdefg.webpagechatprojectbymyself.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

@Component
public class WebSocketApi extends TextWebSocketHandler {
    @Autowired
    private OnlineUserMessage onlineUserMessage;

    @Autowired
    private MessageSessionMapper messageSessionMapper;
    @Autowired
    private MessageMapper messageMapper;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("WebSocketApi 连接异常！" + exception.toString());
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        onlineUserMessage.offline(user.getUserId(), session);
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("WebSocketApi 连接成功！");
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        onlineUserMessage.online(user.getUserId(), session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("WebSocketApi 收到消息！" + message.toString());
        //先获取当前用户信息
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            System.out.println("用户未登录！无法进行消息转发！");
            return;
        }
        //针对请求解析数据，把JSON格式的字符串，转成一个Java中对象
        MessageRequest req = objectMapper.readValue(message.getPayload(), MessageRequest.class);
        if (req.getType().equals("message")) {
            //通过这个方法实际完成消息的转发操作
            transferMessage(user, req);
        } else {
            System.out.println("req.type有误:" + message.getPayload());
        }
    }

    private void transferMessage(User user, MessageRequest req) throws IOException {
        //1.先构造一个MessageResponse对象
        MessageResponse response = new MessageResponse();
        response.setType(req.getType());
        response.setFromId(user.getUserId());
        response.setFromName(user.getUsername());
        response.setSessionId(req.getSessionId());
        response.setContent(req.getContent());
        //这里还需要将response对象转成JSON字符串
        String responseJson = objectMapper.writeValueAsString(response);
        //2.根据SessionId获取到会话中的user都有谁（除自身之外）
        List<Friend> friends = messageSessionMapper.getFriendBySessionId(req.getSessionId(), user.getUserId());
        // 此处注意!!! 上述数据库查询, 会把当前发消息的用户给排除掉. 而最终转发的时候, 则需要也把发送消息的人也发一次.
        // 把当前用户也添加到上述 List 里面
        Friend myself = new Friend();
        myself.setFriendId(user.getUserId());
        myself.setFriendName(user.getUsername());
        friends.add(myself);
        //3.循环转发操作
        for (Friend friend : friends) {
            // 知道了每个用户的 userId, 进一步的查询刚才准备好的 OnlineUserManager, 就知道了对应的 WebSocketSession
            // 从而进行发送消息
            WebSocketSession webSocketSession = onlineUserMessage.getOnlineUser(friend.getFriendId());
            if (webSocketSession == null) {
                // 如果该用户未在线, 则不发送.
                continue;
            }
            //这里还需要包装一下，sendMessage(WebSocketMessage<?> message)传的参数要么是文本或二进制
            webSocketSession.sendMessage(new TextMessage(responseJson));
        }
        // 4. 转发的消息, 还需要放到数据库里. 后续用户如果下线之后, 重新上线, 还可以通过历史消息的方式拿到之前的消息.
        //    需要往 message 表中写入一条记录.
        Message message = new Message();
        message.setFromId(user.getUserId());
        message.setSessionId(req.getSessionId());
        message.setContent(req.getContent());
        // 像自增主键, 还有时间这样的属性, 都可以让 SQL 在数据库中生成
        messageMapper.insertMessage(message);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("WebSocketApi 连接失败！" + status.toString());
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        onlineUserMessage.offline(user.getUserId(), session);
    }
}
